package cn.elwy.rcp.ui.table.listener;

import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TreeItem;

/**
 * @author huangsq
 */
public class TablePaneDropTargetListener implements DropTargetListener {

  LocalSelectionTransfer transfer = LocalSelectionTransfer.getTransfer();
  TreeViewer treeViewer;

  public TablePaneDropTargetListener(TreeViewer treeViewer) {
    this.treeViewer = treeViewer;
  }

  /**
   * dragEnter事件在drag and drop动作开始，并且鼠标进入了target widget的范围内时被调用。
   */
  @Override
  public void dragEnter(DropTargetEvent event) {
    // 在 中应用可以定义default operation.如果一个drop target在创建的时候被指定为
    // 带有DND.DROP_DEFAULT,那么在拖动的过程中如果没有辅助按键被按下，则drop target就是DND.DROP_DEFAULT的。
    // 应用可以通过改变event.detail来指定default operation。如果应用没有具体指定DND.DROP_DEFAULT的操作，
    // 平台会默认将DND.DROP_DEFAULT设置为DND.DROP_MOVE。
    // 另外DND.DROP_DEFAULT的值也可以在dragOperationChanged中设置。
    if (event.detail == DND.DROP_DEFAULT) {
      // 给event.detail赋的值必须是event.operations中的一个,event.operations中
      // 的操作都是DragSource所支持的.
      if ((event.operations & DND.DROP_MOVE) != 0) {
        event.detail = DND.DROP_MOVE;
      } else {
        event.detail = DND.DROP_NONE;
      }
    }
    // drop target可以选择性的按照传输类型来处理.dragEnter event有两个属性
    // event.currentType 是应用设置的默认类型，以TransferData对象形式表现,
    // event.dataTypes 是drag source支持的所有类型的列表，以TransferData数组形式表现,
    // 我们可以将event.currentType设置成event.dataTypes中的任意一个。
    // 这些属性也可以在dragOver, dragOperationChanged以及dropAccept事件中设置。
  }

  // 当光标离开drop target widget时，dragLeave事件发生. 如果你在dragEnter中分配了一些资源，
  // 就应该在dragLeave中释放.dragLeave事件在用户通过Escape键取消Drag and Drop操作时也会发生
  // 刚好在drop操作被执行之前.
  @Override
  public void dragLeave(DropTargetEvent event) {
  }

  // 当用户按下或放开辅助按键时，例如Ctrl, Shift, Command, Option。则dragOperationChanged事件发生。
  // 辅助按键可以改变即将进行的操作。例如：
  // Ctrl key is down, a copy is requested,
  // Ctrl and Shift keys are both down, a link is requested
  // Shift key is down, a move is requested
  // When no modifier keys are pressed, the default operation is requested.
  @Override
  public void dragOperationChanged(DropTargetEvent event) {
    if (event.detail == DND.DROP_DEFAULT) {
      event.detail = DND.DROP_MOVE;
    } else {
      event.detail = DND.DROP_NONE;
    }

    // allow text to be moved but files should only be copied
    if (transfer.isSupportedType(event.currentDataType)) {
      if (event.detail != DND.DROP_MOVE) {
        event.detail = DND.DROP_NONE;
      }
    }
  }

  // dragOver event在光标进入drop target widget时会被重复不停的调用.
  // 如果光标是静止的,dragOver event依然会有规则的按一定时间间隔被调用.
  // 这个方法一般在drop target是Tree或tree时用得比较多，可以根据不同的item而改变操作.
  @Override
  public void dragOver(DropTargetEvent event) {
    // event.feedback设置当widget处于光标下时应该给用户一个什么样的feedback.
    // dragOver event.feedback 值描述
    // DND.FEEDBACK_SELECT 使光标下的item被选中，限于Tree and trees.
    // DND.FEEDBACK_SCROLL 使widget可以滚动以便于用户可以drop在当前看不见的item上，限于Tree and trees.
    // DND.FEEDBACK_EXPAND 使当前光标下的item展开以便于用户在sub item上drop，限于trees.
    // DND.FEEDBACK_INSERT_BEFORE 在item处于光标下之前显示一个插入标记，限于Trees and trees.
    // DND.FEEDBACK_INSERT_AFTER 在item处于光标下之后显示一个插入标记，限于Trees and trees.
    // DND.FEEDBACK_NONE 没有任何效果.
    // event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL;
    // if (transfer.isSupportedType(event.currentDataType)) {
    // System.out.println(transfer.getSelection());
    // }

    if (event.item != null) {
      event.feedback = DND.FEEDBACK_SCROLL;

      TreeItem item = (TreeItem) event.item;
      Point pt = Display.getCurrent().map(null, treeViewer.getTree(), event.x, event.y);
      Rectangle bounds = item.getBounds();
      if (pt.y <= bounds.y + bounds.height / 2) {
        event.feedback |= DND.FEEDBACK_INSERT_BEFORE;
      } else {
        event.feedback |= DND.FEEDBACK_INSERT_AFTER;
      }
    }
  }

  // 如果在之前的事件中得到了有效的操作和currentDataType，那么当用户在drop target上松开鼠标时，drop事件会发生。
  // event.data属性包含了请求到的数据，event.type包含了Transfer的类型.
  // data是event.currentDataType中定义的类型.
  @Override
  public void drop(DropTargetEvent event) {
    if (transfer.isSupportedType(event.currentDataType)) {
      StructuredSelection selection = (StructuredSelection) transfer.getSelection();
      event.data = selection;
      TreeItem item = new TreeItem(treeViewer.getTree(), SWT.NONE);
      item.setText("ttee");
    }
    //
    // Transfer[] types = new Transfer[] { LocalSelectionTransfer.getTransfer() };// 和源一样可定义多种Tranfer
    // DropTarget target = new DropTarget(label, operations);

    // if(transfer.isSupportedType(event.currentDataType)){
    // String text=(String)event.data;
    // TreeItem item=new TreeItem(dropTree,SWT.NONE);
    // item.setText(text);
    // }

    // treeViewer.refresh();
    // target.setTransfer(types);
    // LocalSelectionTransfer.getTransfer().setSelection((ISelection) event.data);
  }

  // dropAccept事件为应用提供了最后一次定义数据类型的机会，定义的数据类型将被返回到drop事件.
  // 这些是通过向event.currentDataType赋event.dataTypes中的值来实现的.
  @Override
  public void dropAccept(DropTargetEvent event) {
  }

}